home *** CD-ROM | disk | FTP | other *** search
- #include <stdio.h>
- #include <ctype.h>
- #include "global.h"
- #include "mbuf.h"
- #include "timer.h"
- #include "netuser.h"
- #include "socket.h"
- #include "cmdparse.h"
- #include "proc.h"
- #include "domain.h"
- #include "commands.h"
-
- extern int errno;
-
- static struct dserver *Dlist; /* List of potential servers */
- static struct dserver *Dserver; /* Current one being used */
- static char *Dsuffix; /* Default suffix for names without periods */
- static int Dsocket; /* Socket to use for domain queries */
- static struct proc *Drx; /* Task ID of domain receiver */
- static int Ddebug = 0;
- static char *Dtypes[] = {
- "",
- "A",
- "NS",
- "MD",
- "MF",
- "CNAME",
- "SOA",
- "MB",
- "MG",
- "MR",
- "NULL",
- "WKS",
- "PTR",
- "HINFO",
- "MINFO",
- "MX",
- "TXT"
- };
- static int Ndtypes = 17;
- static char delim[] = " \t\r\n";
- static struct {
- char *name;
- int32 address;
- } cache;
-
- static void addit __ARGS((FILE *fp,struct rr *rrp1));
- static struct rr *dfind __ARGS((FILE *dbase,char *name,int type));
- static int dn_expand __ARGS((char *msg,char *eom,char *compressed,char *full,int fullen));
- static int doadds __ARGS((int argc,char *argv[],void *p));
- static int dodropds __ARGS((int argc,char *argv[],void *p));
- static int dosuffix __ARGS((int argc,char *argv[],void *p));
- static int dodtrace __ARGS((int argc,char *argv[],void *p));
- static void drx __ARGS((int unused, void *u,void *p));
- static struct dserver *dslookup __ARGS((int32 server));
- static void free_dhdr __ARGS((struct dhdr *dp));
- static void free_qu __ARGS((struct quest *qp));
- static void free_rr __ARGS((struct rr *rrp));
- static char *getq __ARGS((struct quest *qp,char *msg,char *cp));
- static struct rr *getrr __ARGS((FILE *fp));
- static int ntohdomain __ARGS((struct dhdr *dhdr,struct mbuf **bpp));
- static char *ntohrr __ARGS((struct rr *rrp,char *msg,char *cp));
- static void proc_answer __ARGS((struct dserver *dp,struct mbuf *bp));
- static void putrr __ARGS((FILE *fp,struct rr *rrp));
- static int res_mkquery __ARGS((int16 op,char *dname,int16 class,int16 type,
- char *data,int16 datalen,int16 newrr,char *buffer,int16 buflen));
- static int rrcmp __ARGS((struct rr *rr1,struct rr *rr2));
-
- static struct cmds Dcmds[] = {
- "addserver", doadds, 0, 0, NULLCHAR,
- "dropserver", dodropds, 0, 0, NULLCHAR,
- "suffix", dosuffix, 0, 0, NULLCHAR,
- "trace", dodtrace, 0, 0, NULLCHAR,
- NULLCHAR,
- };
- int
- dodtrace(argc,argv,p)
- int argc;
- char *argv[];
- void *p;
- {
- return setbool(&Ddebug,"Domain trace",argc,argv);
- }
- int
- dodomain(argc,argv,p)
- int argc;
- char *argv[];
- void *p;
- {
- return subcmd(Dcmds,argc,argv,p);
- }
- static int
- dosuffix(argc,argv,p)
- int argc;
- char *argv[];
- void *p;
- {
- if(argc < 2){
- if(Dsuffix != NULLCHAR)
- printf("%s\n",Dsuffix);
- return 0;
- }
- free(Dsuffix);
- Dsuffix = strdup(argv[1]);
- return 0;
- }
- static int
- doadds(argc,argv,p)
- int argc;
- char *argv[];
- void *p;
- {
- struct dserver *dp;
- int32 address;
-
- if((address = resolve(argv[1])) == 0){
- printf("Resolver %s unknown\n",argv[1]);
- return 1;
- }
- dp = (struct dserver *)calloc(1,sizeof(struct dserver));
- dp->address = address;
- dp->srtt = (5L * 1000) / MSPTICK; /* About 5 sec */
- dp->timeout = dp->srtt * 2;
- dp->mdev = 0;
- dp->next = Dlist;
- if(dp->next != NULLDOM)
- dp->next->prev = dp;
- Dlist = dp;
- Dserver = dp; /* Make this the first one we try next */
- if(Drx == NULLPROC){
- /* Start domain task upon first addserver */
- Drx = newproc("Domain",1024,drx,0,NULL,NULL);
- }
- return 0;
- }
- static int
- dodropds(argc,argv,p)
- int argc;
- char *argv[];
- void *p;
- {
- struct dserver *dp;
- int32 addr;
-
- addr = resolve(argv[1]);
- for(dp = Dlist;dp != NULLDOM;dp = dp->next)
- if(addr == dp->address)
- break;
-
- if(dp == NULLDOM){
- printf("Not found\n");
- return 1;
- }
- if(dp->prev != NULLDOM)
- dp->prev->next = dp->next;
- else
- Dlist = dp->next;
- if(dp->next != NULLDOM)
- dp->next->prev = dp->prev;
-
- if(Dserver == dp)
- Dserver = Dlist;
- free((char *)dp);
- return 0;
- }
-
- /* Search local domain file for resource record of specified type.
- * If a record is found, the domain file pointer is left just after it. If
- * not, the file is rewound.
- */
- static struct rr *
- dfind(dbase,name,type)
- FILE *dbase;
- char *name;
- int type;
- {
- struct rr *rrp;
- int nlen;
-
- /* Search file */
- while((rrp = getrr(dbase)) != NULLRR){
- if((nlen = strlen(name)) == strlen(rrp->name)
- && strnicmp(name,rrp->name,nlen) == 0
- && rrp->class == CLASS_IN
- && rrp->type == type)
- break;
- free_rr(rrp);
- pwait(NULL); /* Give up CPU for a while, this is slow */
- }
- if(rrp == NULLRR)
- rewind(dbase);
- return rrp;
- }
- static struct rr *
- getrr(fp)
- FILE *fp;
- {
- char *line,*strtok();
- struct rr *rrp;
- char *name,*ttl,*class,*type,*data;
- int i;
-
- line = malloc(256);
- /* Search file */
- while(fgets(line,256,fp),!feof(fp)){
- if(line[0] != '#')
- break;
- }
- if(feof(fp) || (rrp = (struct rr *)calloc(1,sizeof(struct rr))) == NULLRR){
- free(line);
- return NULLRR;
- }
- name = strtok(line,delim);
- ttl = strtok(NULLCHAR,delim);
- class = strtok(NULLCHAR,delim);
- type = strtok(NULLCHAR,delim);
- data = strtok(NULLCHAR,delim);
-
- rrp->name = strdup(name);
- if(!isdigit(ttl[0])){
- /* Optional ttl field is missing; slide the other fields over */
- data = type;
- type = class;
- class = ttl;
- ttl = NULLCHAR;
- } else {
- rrp->ttl = atol(ttl);
- }
- for(i=0;i<NRLIST;i++){
- if(strcmp(type,Dtypes[i]) == 0){
- rrp->type = i;
- break;
- }
- }
- if(strcmp(class,"IN") == 0)
- rrp->class = CLASS_IN;
-
- if(data == NULLCHAR){
- /* Empty record, just return */
- free(line);
- return rrp;
- }
- switch(rrp->type){
- case TYPE_CNAME:
- case TYPE_MB:
- case TYPE_MG:
- case TYPE_MR:
- case TYPE_NS:
- case TYPE_PTR:
- case TYPE_TXT:
- rrp->rdlength = strlen(data);
- rrp->rdata.name = strdup(data);
- break;
- case TYPE_A:
- rrp->rdlength = 4;
- rrp->rdata.addr = aton(data);
- break;
- case TYPE_HINFO:
- rrp->rdlength = strlen(data);
- rrp->rdata.hinfo.cpu = strdup(data);
- if((data = strtok(NULLCHAR,delim)) != NULLCHAR){
- rrp->rdlength += strlen(data);
- rrp->rdata.hinfo.os = strdup(data);
- }
- break;
- case TYPE_MX:
- rrp->rdata.mx.pref = atoi(data);
- rrp->rdlength = 2;
-
- /* Get domain name of exchanger */
- if((data = strtok(NULLCHAR,delim)) != NULLCHAR){
- rrp->rdlength += strlen(data);
- rrp->rdata.mx.exch = strdup(data);
- }
- break;
- case TYPE_SOA:
- /* Get domain name of master name server */
- rrp->rdlength = strlen(data);
- rrp->rdata.soa.mname = strdup(data);
-
- /* Get domain name of irresponsible person */
- if((data = strtok(NULLCHAR,delim)) != NULLCHAR){
- rrp->rdata.soa.rname = strdup(data);
- rrp->rdlength += strlen(data);
- }
- data = strtok(NULLCHAR,delim);
- rrp->rdata.soa.serial = atol(data);
- data = strtok(NULLCHAR,delim);
- rrp->rdata.soa.refresh = atol(data);
- data = strtok(NULLCHAR,delim);
- rrp->rdata.soa.retry = atol(data);
- data = strtok(NULLCHAR,delim);
- rrp->rdata.soa.expire = atol(data);
- data = strtok(NULLCHAR,delim);
- rrp->rdata.soa.minimum = atol(data);
- rrp->rdlength += 20;
- break;
- }
- free(line);
- return rrp;
- }
- /* Search for address record in local database, looking first for PTR
- * and CNAME records. Return values:
- * 0xffffffff Not found (domain name may exist, but we don't know yet)
- * 0 Domain name definitely doesn't exist (we have a null record)
- */
- int32
- dresolve(name)
- char *name;
- {
- register struct rr *rrp;
- char *pname = NULLCHAR;
- char *cname = NULLCHAR;
- int32 result;
- FILE *dbase;
-
- if(cache.name != NULLCHAR && strcmp(cache.name,name) == 0)
- return cache.address;
-
- if((dbase = fopen(Dfile,READ_TEXT)) == NULLFILE)
- return 0xffffffff;
-
- /* This code can handle a few weird cases. It works when there's
- * a PTR to a CNAME to an A record, as well as when there's a
- * a CNAME to a PTR to an A. But it allows only one of each kind
- * of indirection to prevent infinite loops.
- */
- while((rrp = dfind(dbase,name,TYPE_A)) == NULLRR){
- /* An address record didn't exist, let's see if it's an alias */
- if(cname == NULLCHAR && (rrp = dfind(dbase,name,TYPE_CNAME)) != NULLRR){
- if((cname = strdup(rrp->rdata.name)) == NULLCHAR)
- break;
- name = cname;
- rewind(dbase);
- free_rr(rrp);
- continue; /* Try again */
- }
- /* Lacking that, try a pointer entry... */
- if(pname == NULLCHAR && (rrp = dfind(dbase,name,TYPE_PTR)) != NULLRR){
- if((pname = strdup(rrp->rdata.name)) == NULLCHAR)
- break;
- name = pname;
- rewind(dbase);
- free_rr(rrp);
- continue;
- }
- /* Nope, nothing. Give up */
- break;
- }
- fclose(dbase);
- free(pname);
- free(cname);
-
- if(rrp == NULLRR){
- result = 0xffffffff; /* No record in database */
- } else {
- if(rrp->rdlength == 0)
- result = 0; /* Negative response record */
- else
- result = rrp->rdata.addr; /* Normal return */
- free(cache.name);
- cache.name = strdup(name);
- cache.address = result;
- free_rr(rrp);
- }
- return result;
- }
-
- /* Main entry point for domain name -> address resolution. Returns 0 if
- * name is definitely not valid.
- */
- int32
- resolve(name)
- char *name;
- {
- char *buf;
- int32 addr;
- struct dserver *dp;
- int len;
- struct sockaddr_in server;
- char *tname = NULLCHAR;
- char *pname = NULLCHAR;
-
- if(name == NULLCHAR)
- return 0;
-
- if(*name == '[')
- return aton(name + 1);
-
- if(strchr(name,'.') == NULLCHAR && Dsuffix != NULLCHAR){
- /* Append default suffix */
- tname = malloc(strlen(name)+strlen(Dsuffix)+2);
- sprintf(tname,"%s.%s",name,Dsuffix);
- name = tname;
- }
- if(name[strlen(name)-1] != '.'){
- /* Append trailing dot */
- pname = malloc(strlen(name)+2);
- sprintf(pname,"%s.",name);
- name = pname;
- }
- dp = Dserver;
- while((addr = dresolve(name)) == 0xffffffff){
- if(dp == NULLDOM){
- addr = 0; /* Unknown, and no servers */
- break;
- }
- /* Not in file, send query */
- buf = malloc(512);
- len = res_mkquery(0,name,CLASS_IN,TYPE_A,NULLCHAR,0,0,buf,512);
- server.sin_family = AF_INET;
- server.sin_port = IPPORT_DOMAIN;
- server.sin_addr.s_addr = dp->address;
- sendto(Dsocket,buf,len,0,(char *)&server,sizeof(server));
- free(buf);
- alarm(dp->timeout);
- /* Wait for something to happen */
- len = pwait(&Dsocket);
- alarm(0L);
- switch(len){
- case -1:
- addr = 0;
- goto quit;
- case 0:
- break;
- case 1:
- /* Timeout; back off this one and try another server */
- dp->timeout <<= 1;
- if((dp = dp->next) == NULLDOM)
- dp = Dlist;
- break;
- }
- }
- quit: free(tname);
- free(pname);
- return addr;
- }
- static int
- res_mkquery(op,dname,class,type,data,datalen,newrr,buffer,buflen)
- int16 op; /* operation */
- char *dname; /* Domain name */
- int16 class; /* Class of inquiry (IN, etc) */
- int16 type; /* Type of inquiry (A, MX, etc) */
- char *data;
- int16 datalen;
- int16 newrr;
- char *buffer; /* Area for query */
- int16 buflen; /* Length of same */
- {
- char *cp,*cp1;
- int16 parameter;
- int16 dlen,len;
-
- cp = buffer;
- cp = put16(cp,(int16)Clock); /* Use clock for timestamping */
- parameter = 0x100; /* Recursion desired */
- cp = put16(cp,parameter);
- cp = put16(cp,1);
- cp = put16(cp,0);
- cp = put16(cp,0);
- cp = put16(cp,0);
- dlen = strlen(dname);
- for(;;){
- /* Look for next dot */
- cp1 = strchr(dname,'.');
- if(cp1 != NULLCHAR)
- len = cp1-dname; /* More to come */
- else
- len = dlen; /* Last component */
- *cp++ = len; /* Write length of component */
- if(len == 0)
- break;
- /* Copy component up to (but not including) dot */
- strncpy(cp,dname,len);
- cp += len;
- if(cp1 == NULLCHAR){
- *cp++ = 0; /* Last one; write null and finish */
- break;
- }
- dname += len+1;
- dlen -= len+1;
- }
- cp = put16(cp,type);
- cp = put16(cp,class);
- return cp - buffer;
- }
- /* Convert a compressed domain name to the human-readable form */
- static int
- dn_expand(msg,eom,compressed,full,fullen)
- char *msg; /* Complete domain message */
- char *eom;
- char *compressed; /* Pointer to compressed name */
- char *full; /* Pointer to result buffer */
- int fullen; /* Length of same */
- {
- unsigned int slen; /* Length of current segment */
- register char *cp;
- unsigned int clen = 0; /* Total length of compressed name */
- int indirect = 0; /* Set if indirection encountered */
- int nseg = 0; /* Total number of segments in name */
-
- cp = compressed;
- for(;;){
- slen = uchar(*cp++); /* Length of this segment */
- if(!indirect)
- clen++;
- if((slen & 0xc0) == 0xc0){
- if(!indirect)
- clen++;
- indirect = 1;
- /* Follow indirection */
- cp = &msg[((slen & 0x3f)<<8) + uchar(*cp)];
- slen = uchar(*cp++);
- }
- if(slen == 0) /* zero length == all done */
- break;
- fullen -= slen + 1;
- if(fullen < 0)
- return -1;
- if(!indirect)
- clen += slen;
- while(slen-- != 0)
- *full++ = *cp++;
- *full++ = '.';
- nseg++;
- }
- if(nseg == 0){
- /* Root name; represent as single dot */
- *full++ = '.';
- fullen--;
- }
- *full++ = '\0';
- fullen--;
- return clen; /* Length of compressed message */
- }
- /* Process to receive all domain server replies */
- static void
- drx()
- {
- struct sockaddr_in sock,from;
- int fromlen;
- struct mbuf *bp;
- struct dserver *dp,*dslookup();
- int foo;
-
- Dsocket = socket(AF_INET,SOCK_DGRAM,0);
- sock.sin_family = AF_INET;
- sock.sin_addr.s_addr = Ip_addr;
- sock.sin_port = IPPORT_DOMAIN;
- if(bind(Dsocket,(char *)&sock,sizeof(sock)) == -1){
- printf("Domain: can't bind (is ip address set?)\n");
- Drx = NULLPROC;
- return;
- }
- for(;;){
- fromlen = sizeof(from);
- foo = recv_mbuf(Dsocket,&bp,0,0,(char *)&from,&fromlen);
- if(Ddebug)
- printf("domain: %u bytes from %s\n",foo,
- psocket((struct sockaddr *)&from));
- if((dp = dslookup(from.sin_addr.s_addr)) == NULLDOM){
- /* Unknown server */
- if(Ddebug)
- printf("Unknown domain server!\n");
- continue;
- }
- Dserver = dp; /* We know this one is good */
- proc_answer(dp,bp);
- }
- }
- static void
- proc_answer(dp,bp)
- struct dserver *dp;
- struct mbuf *bp;
- {
- FILE *fp;
- struct dhdr dhdr;
- int i;
- int16 rtt;
- long ttl = 500; /* Default TTL for negative records without SOA */
- struct rr *rrp;
- struct quest *qp;
-
- ntohdomain(&dhdr,&bp);
-
- /* Compute and update the round trip time */
- rtt = (int16)Clock - dhdr.id;
- dp->srtt = (7 * dp->srtt + rtt) >> 3;
- dp->timeout = 2*dp->srtt;
-
- if(Ddebug){
- printf("response id %u (rtt %lu sec) qr %u opcode %u aa %u tc %u rd %u ra %u rcode %u\n",
- dhdr.id,((long)rtt * MSPTICK)/1000,
- dhdr.qr,dhdr.opcode,dhdr.aa,dhdr.tc,dhdr.rd,
- dhdr.ra,dhdr.rcode);
- printf("%u questions:\n",dhdr.qdcount);
- for(i=0;i< dhdr.qdcount;i++){
- qp = dhdr.qlist[i];
- printf("%s type %u class %u\n",qp->qname,
- qp->qtype,qp->qclass);
- }
- }
- if(dhdr.qr == QUERY){
- /* A server will eventually go here. */
- free_dhdr(&dhdr);
- return;
- }
- fp = fopen(Dfile,APPEND_TEXT);
- if(fp == NULLFILE){
- printf("Can't append to %s!!\n",Dfile);
- free_dhdr(&dhdr);
- return;
- }
- if(Ddebug)
- printf("%u answers:\n",dhdr.ancount);
- for(i=0;i< dhdr.ancount;i++){
- rrp = dhdr.ans[i];
- if(Ddebug)
- putrr(stdout,rrp);
- if(rrp->type == TYPE_SOA)
- ttl = rrp->ttl;
- addit(fp,rrp);
- }
- if(Ddebug)
- printf("%u authority:\n",dhdr.nscount);
- for(i=0;i< dhdr.nscount;i++){
- rrp = dhdr.ns[i];
- if(Ddebug){
- putrr(stdout,rrp);
- fflush(stdout);
- }
- if(rrp->type == TYPE_SOA)
- ttl = rrp->ttl;
- addit(fp,rrp);
- }
- if(Ddebug)
- printf("%u additional:\n",dhdr.arcount);
- for(i=0;i< dhdr.arcount;i++){
- rrp = dhdr.add[i];
- if(Ddebug){
- putrr(stdout,rrp);
- fflush(stdout);
- }
- if(rrp->type == TYPE_SOA)
- ttl = rrp->ttl;
- addit(fp,rrp);
- }
- if(dhdr.aa && (dhdr.rcode == NAME_ERROR || dhdr.ancount == 0)){
- /* Add negative reply to file. This assumes that there was
- * only one question, which is true for all questions we send.
- */
- qp = dhdr.qlist[0];
- rrp = (struct rr *)calloc(1,sizeof(struct rr));
- rrp->name = strdup(qp->qname);
- rrp->type = qp->qtype;
- rrp->class = qp->qclass;
- rrp->ttl = ttl;
- rrp->rdlength = 0; /* no data */
- addit(fp,rrp);
- free_rr(rrp);
- }
- fclose(fp);
- free_dhdr(&dhdr);
- psignal(&Dsocket,0); /* Alert anyone waiting for results */
- }
- static int
- ntohdomain(dhdr,bpp)
- struct dhdr *dhdr;
- struct mbuf **bpp;
- {
- int16 tmp,len,i;
- char *msg,*cp;
-
- len = len_mbuf(*bpp);
- msg = malloc(len);
- pullup(bpp,msg,len);
- memset((char *)dhdr,0,sizeof(*dhdr));
-
- dhdr->id = get16(&msg[0]);
- tmp = get16(&msg[2]);
- if(tmp & 0x8000)
- dhdr->qr = 1;
- dhdr->opcode = (tmp >> 11) & 0xf;
- if(tmp & 0x0400)
- dhdr->aa = 1;
- if(tmp & 0x0200)
- dhdr->tc = 1;
- if(tmp & 0x0100)
- dhdr->rd = 1;
- if(tmp & 0x0080)
- dhdr->ra = 1;
- dhdr->rcode = tmp & 0xf;
- dhdr->qdcount = get16(&msg[4]);
- dhdr->ancount = get16(&msg[6]);
- dhdr->nscount = get16(&msg[8]);
- dhdr->arcount = get16(&msg[10]);
-
- /* Now parse the variable length sections */
- cp = &msg[12];
-
- /* Question section */
- if(dhdr->qdcount != 0)
- dhdr->qlist = (struct quest **)malloc(dhdr->qdcount *
- sizeof(struct quest *));
- for(i=0;i<dhdr->qdcount;i++){
- dhdr->qlist[i] = (struct quest *)malloc(sizeof(struct quest));
- if((cp = getq(dhdr->qlist[i],msg,cp)) == NULLCHAR){
- free(msg);
- return -1;
- }
- }
- /* Answer section */
- if(dhdr->ancount != 0)
- dhdr->ans = (struct rr **)malloc(dhdr->ancount *
- sizeof(struct rr *));
- for(i=0;i<dhdr->ancount;i++){
- dhdr->ans[i] = (struct rr *)malloc(sizeof(struct rr));
- if((cp = ntohrr(dhdr->ans[i],msg,cp)) == NULLCHAR){
- free(msg);
- return -1;
- }
- }
- /* Name server (authority) section */
- if(dhdr->nscount != 0)
- dhdr->ns = (struct rr **)malloc(dhdr->nscount *
- sizeof(struct rr *));
- for(i=0;i<dhdr->nscount;i++){
- dhdr->ns[i] = (struct rr *)malloc(sizeof(struct rr));
- if((cp = ntohrr(dhdr->ns[i],msg,cp)) == NULLCHAR){
- free(msg);
- return -1;
- }
- }
- /* Additional section */
- if(dhdr->arcount != 0)
- dhdr->add = (struct rr **)malloc(dhdr->arcount *
- sizeof(struct rr *));
- for(i=0;i<dhdr->arcount;i++){
- dhdr->add[i] = (struct rr *)malloc(sizeof(struct rr));
- if((cp = ntohrr(dhdr->add[i],msg,cp)) == NULLCHAR){
- free(msg);
- return -1;
- }
- }
- free(msg);
- return 0;
- }
- static char *
- getq(qp,msg,cp)
- struct quest *qp;
- char *msg;
- char *cp;
- {
- int len;
- char *name;
-
- name = malloc(512);
- len = dn_expand(msg,NULLCHAR,cp,name,512);
- if(len == -1){
- free(name);
- return NULLCHAR;
- }
- cp += len;
- qp->qname = strdup(name);
- qp->qtype = get16(cp);
- cp += 2;
- qp->qclass = get16(cp);
- cp += 2;
- free(name);
- return cp;
- }
- /* Read a resource record from a domain message into a host structure */
- static char *
- ntohrr(rrp,msg,cp)
- struct rr *rrp; /* Pointer to allocated resource record structure */
- char *msg; /* Pointer to beginning of domain message */
- char *cp; /* Pointer to start of encoded RR record */
- {
- int len;
- char *name;
-
- if((name = malloc(512)) == NULLCHAR)
- return NULLCHAR;
- if((len = dn_expand(msg,NULLCHAR,cp,name,512)) == -1){
- free(name);
- return NULLCHAR;
- }
- cp += len;
- rrp->name = strdup(name);
- rrp->type = get16(cp);
- cp += 2;
- rrp->class = get16(cp);
- cp+= 2;
- rrp->ttl = get32(cp);
- cp += 4;
- rrp->rdlength = get16(cp);
- cp += 2;
- switch(rrp->type){
- case TYPE_CNAME:
- case TYPE_MB:
- case TYPE_MG:
- case TYPE_MR:
- case TYPE_NS:
- case TYPE_PTR:
- /* These types all consist of a single domain name;
- * convert it to ascii format
- */
- len = dn_expand(msg,NULLCHAR,cp,name,512);
- if(len == -1){
- free(name);
- return NULLCHAR;
- }
- rrp->rdata.name = strdup(name);
- cp += len;
- break;
- case TYPE_A:
- /* Just read the address directly into the structure */
- rrp->rdata.addr = get32(cp);
- cp += 4;
- break;
- case TYPE_HINFO:
- rrp->rdata.hinfo.cpu = strdup(cp);
- cp += strlen(cp) + 1;
-
- rrp->rdata.hinfo.os = strdup(cp);
- cp += strlen(cp) + 1;
- break;
- case TYPE_MX:
- rrp->rdata.mx.pref = get16(cp);
- cp += 2;
- /* Get domain name of exchanger */
- len = dn_expand(msg,NULLCHAR,cp,name,512);
- if(len == -1){
- free(name);
- return NULLCHAR;
- }
- rrp->rdata.mx.exch = strdup(name);
- cp += len;
- break;
- case TYPE_SOA:
- /* Get domain name of name server */
- len = dn_expand(msg,NULLCHAR,cp,name,512);
- if(len == -1){
- free(name);
- return NULLCHAR;
- }
- rrp->rdata.soa.mname = strdup(name);
- cp += len;
-
- /* Get domain name of responsible person */
- len = dn_expand(msg,NULLCHAR,cp,name,512);
- if(len == -1){
- free(name);
- return NULLCHAR;
- }
- rrp->rdata.soa.rname = strdup(name);
- cp += len;
-
- rrp->rdata.soa.serial = get32(cp);
- cp += 4;
- rrp->rdata.soa.refresh = get32(cp);
- cp += 4;
- rrp->rdata.soa.retry = get32(cp);
- cp += 4;
- rrp->rdata.soa.expire = get32(cp);
- cp += 4;
- rrp->rdata.soa.minimum = get32(cp);
- cp += 4;
- break;
- case TYPE_TXT:
- /* Just stash */
- rrp->rdata.data = malloc(rrp->rdlength);
- memcpy(rrp->rdata.data,cp,rrp->rdlength);
- cp += rrp->rdlength;
- break;
- default:
- /* Ignore */
- cp += rrp->rdlength;
- break;
- }
- free(name);
- return cp;
- }
- /* Print a resource record */
- static void
- putrr(fp,rrp)
- FILE *fp;
- struct rr *rrp;
- {
- if(fp == NULLFILE || rrp == NULLRR)
- return;
-
- fprintf(fp,"%s\t%lu",rrp->name,rrp->ttl);
- if(rrp->class == CLASS_IN)
- fprintf(fp,"\tIN");
- else
- fprintf(fp,"\t%u",rrp->class);
- if(rrp->type < Ndtypes)
- fprintf(fp,"\t%s",Dtypes[rrp->type]);
- else
- fprintf(fp,"\t%u",rrp->type);
- if(rrp->rdlength == 0){
- /* Null data portion, indicates nonexistent record */
- fprintf(fp,"\n");
- return;
- }
- switch(rrp->type){
- case TYPE_CNAME:
- case TYPE_MB:
- case TYPE_MG:
- case TYPE_MR:
- case TYPE_NS:
- case TYPE_PTR:
- case TYPE_TXT:
- /* These are all printable text strings */
- fprintf(fp,"\t%s\n",rrp->rdata.data);
- break;
- case TYPE_A:
- fprintf(fp,"\t%s\n",inet_ntoa(rrp->rdata.addr));
- break;
- case TYPE_MX:
- fprintf(fp,"\t%u\t%s\n",rrp->rdata.mx.pref,
- rrp->rdata.mx.exch);
- break;
- case TYPE_SOA:
- fprintf(fp,"\t%s\t%s\t%lu\t%lu\t%lu\t%lu\t%lu\n",
- rrp->rdata.soa.mname,rrp->rdata.soa.rname,
- rrp->rdata.soa.serial,rrp->rdata.soa.refresh,
- rrp->rdata.soa.retry,rrp->rdata.soa.expire,
- rrp->rdata.soa.minimum);
- break;
- default:
- fprintf(fp,"\n");
- break;
- }
- }
- /* Add a record to the database only if it doesn't already exist */
- static void
- addit(fp,rrp1)
- FILE *fp;
- struct rr *rrp1;
- {
- register struct rr *rrp;
-
- rewind(fp);
- while((rrp = dfind(fp,rrp1->name,rrp1->type)) != NULLRR){
- if(rrcmp(rrp,rrp1) == 0){
- free_rr(rrp);
- return;
- }
- free_rr(rrp);
- }
- fseek(fp,0L,2);
- putrr(fp,rrp1);
- }
- static struct dserver *
- dslookup(server)
- int32 server;
- {
- struct dserver *dp;
-
- for(dp = Dlist;dp != NULLDOM;dp = dp->next)
- if(dp->address == server)
- break;
- return dp;
- }
- /* Free a domain message */
- static void
- free_dhdr(dp)
- struct dhdr *dp;
- {
- int i;
-
- if(dp->qdcount != 0){
- for(i=0;i<dp->qdcount;i++)
- free_qu(dp->qlist[i]);
- free((char *)dp->qlist);
- }
- if(dp->ancount != 0){
- for(i=0;i<dp->ancount;i++)
- free_rr(dp->ans[i]);
- free((char *)dp->ans);
- }
- if(dp->nscount != 0){
- for(i=0;i<dp->nscount;i++)
- free_rr(dp->ns[i]);
- free((char *)dp->ns);
- }
- if(dp->arcount != 0){
- for(i=0;i<dp->arcount;i++)
- free_rr(dp->add[i]);
- free((char *)dp->add);
- }
- }
-
- /* Free a question record */
- static void
- free_qu(qp)
- struct quest *qp;
- {
- free(qp->qname);
- free((char *)qp);
- }
-
- /* Free a resource record */
- static void
- free_rr(rrp)
- struct rr *rrp;
- {
- if(rrp == NULLRR)
- return;
- free(rrp->name);
- if(rrp->rdlength != 0){
- switch(rrp->type){
- case TYPE_CNAME:
- case TYPE_MB:
- case TYPE_MG:
- case TYPE_MR:
- case TYPE_NS:
- case TYPE_PTR:
- free(rrp->rdata.name);
- break;
- case TYPE_A:
- break; /* Nothing allocated in rdata section */
- case TYPE_HINFO:
- free(rrp->rdata.hinfo.cpu);
- free(rrp->rdata.hinfo.os);
- break;
- case TYPE_MX:
- free(rrp->rdata.mx.exch);
- break;
- case TYPE_SOA:
- free(rrp->rdata.soa.mname);
- free(rrp->rdata.soa.rname);
- break;
- case TYPE_TXT:
- free(rrp->rdata.data);
- break;
- }
- }
- free((char *)rrp);
- }
- /* Compare two resource records, returning 0 if equal, nonzero otherwise */
- static int
- rrcmp(rr1,rr2)
- register struct rr *rr1,*rr2;
- {
- int i;
-
- if(rr1 == NULLRR || rr2 == NULLRR)
- return -1;
- if((i = strlen(rr1->name)) != strlen(rr2->name))
- return 1;
- if((i = strnicmp(rr1->name,rr2->name,i)) != 0)
- return i;
- if(rr1->type != rr2->type)
- return 2;
- if(rr1->class != rr2->class)
- return 3;
- /* Note: rdlengths are not compared because they vary depending
- * on the representation (ASCII or encoded) this record was
- * generated from.
- */
- switch(rr1->type){
- case TYPE_A:
- i = rr1->rdata.addr != rr2->rdata.addr;
- break;
- case TYPE_SOA:
- i = rr1->rdata.soa.serial != rr2->rdata.soa.serial;
- break;
- case TYPE_HINFO:
- i = strcmp(rr1->rdata.hinfo.cpu,rr2->rdata.hinfo.cpu) ||
- strcmp(rr1->rdata.hinfo.os,rr2->rdata.hinfo.os);
- break;
- case TYPE_MX:
- i = strcmp(rr1->rdata.mx.exch,rr2->rdata.mx.exch);
- break;
- case TYPE_MB:
- case TYPE_MG:
- case TYPE_MR:
- case TYPE_NULL:
- case TYPE_WKS:
- case TYPE_PTR:
- case TYPE_MINFO:
- case TYPE_TXT:
- case TYPE_NS:
- i = strcmp(rr1->rdata.data,rr2->rdata.data);
- break;
- case TYPE_MD:
- case TYPE_MF:
- case TYPE_CNAME:
- i = strcmp(rr1->rdata.data,rr2->rdata.data);
- break;
- }
- return i;
- }
-